package lk.icta.core.dao.impl;

import lk.icta.common.AppConstants;
import lk.icta.common.dao.PreloadableDAO;
import lk.icta.common.dao.impl.BaseDAO;
import lk.icta.core.dao.AlienationMethodDAO;
import lk.icta.core.entity.AlienationMethod;
import lk.icta.user.entity.User;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Date;

/**
 * @author Duminda Dharmakeerthi
 * @author Sisiruwan Senadeera
 */
public class AlienationMethodDAOImpl extends BaseDAO implements AlienationMethodDAO, PreloadableDAO {
    private final Map<Integer, String> siNames = new HashMap<Integer, String>();
    private final Map<Integer, String> enNames = new HashMap<Integer, String>();
    private final Map<Integer, String> taNames = new HashMap<Integer, String>();

    @Transactional(propagation = Propagation.SUPPORTS)
    public AlienationMethod getAlienationMethodById(int id, User user) {
        logger.debug("Loading Alienation Method [Id: {}]", id);
        return em.find(AlienationMethod.class, id);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public Map<Integer, String> getAllAlienationMethods(String language, User user) {
        Map<Integer, String> result = null;
        if (AppConstants.SINHALA.equals(language)) {
            return siNames;
        } else if (AppConstants.ENGLISH.equals(language)) {
            return enNames;
        } else if (AppConstants.TAMIL.equals(language)) {
            return taNames;
        } else {
            return result;
        }
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public Map<Integer, String> getAllAlienationMethods(String language) {
        Map<Integer, String> result = null;
        if (AppConstants.SINHALA.equals(language)) {
            return siNames;
        } else if (AppConstants.ENGLISH.equals(language)) {
            return enNames;
        } else if (AppConstants.TAMIL.equals(language)) {
            return taNames;
        } else {
            return result;
        }
    }

    /**
     * Loads all values from the database table into a cache
     */
    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public void preload() {

        Query query = em.createQuery("SELECT a FROM AlienationMethod a");
        List<AlienationMethod> results = query.getResultList();

        for (AlienationMethod d : results) {
            updateCache(d);
        }

    }

    private void updateCache(AlienationMethod d) {
        int id = d.getId();

        siNames.put(id, d.getSiName());
        enNames.put(id, d.getEnName());
        taNames.put(id, d.getTaName());
    }


    /**
     * Adding an Alienation Method
     *
     * @param alienationMethod The AlienationMethod Object to be added
     */

    @Transactional(propagation = Propagation.MANDATORY)
    public void addAlienationMethod(AlienationMethod alienationMethod,User user) {
        logger.debug("Adding a Alianation Method {}", alienationMethod.getId());
        alienationMethod.getLifeCycleInfo().setCreatedTimeStamp(new Date());
        alienationMethod.getLifeCycleInfo().setCreatedUser(user);
        alienationMethod.getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
        alienationMethod.getLifeCycleInfo().setLastUpdatedUser(user);
        em.persist(alienationMethod);
    }

    /**
     * To get all the updatable Alienation Methods according to the language
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    public List<AlienationMethod> getAllUpdatableAlienationMethods() {
        Query query = em.createNamedQuery("getAllUpdatableAlienationMethods");
        List<AlienationMethod> results = query.getResultList();
        return results;
    }

    /**
     * Updating an existing Alienation Method
     *
     * @param alienationMethod The AlienationMethod to be updated.
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    public void updateAlienationMethod(AlienationMethod alienationMethod, User user) {
        alienationMethod.getLifeCycleInfo().setLastUpdatedTimeStamp(new Date());
        alienationMethod.getLifeCycleInfo().setLastUpdatedUser(user);
        em.merge(alienationMethod);
    }

}

